package com.starleague.battletech.hexagonal.android;

import java.util.ArrayList;
import java.util.EnumMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.text.TextPaint;
import android.util.Log;

import com.starleague.battletech.android.R;
import com.starleague.battletech.hexagonal.BattletechHexTerrainType;
import com.starleague.battletech.hexagonal.IBattletechHex;
import com.starleague.battletech.hexagonal.IBattletechHexTerrain;
import com.starleague.hexagonal.IHex;
import com.starleague.hexagonal.android.IHexPainter;
import com.starleague.hexagonal.flat.android.FlatHexGridMetrics;

public class BattletechHexPainter
        implements IHexPainter
{
    private final FlatHexGridMetrics flatHexGridMetrics;
    private final Paint bitmapPaint = new Paint();
    private final TextPaint textPaint = new TextPaint();
    private final Rect textBoundsRect = new Rect();

    // private SparseArray<Bitmap> idBitmaps = new SparseArray<Bitmap>();
    private final Map<BattletechHexTerrainType, Bitmap[]> terrainBitmapMap = new EnumMap<BattletechHexTerrainType, Bitmap[]>(BattletechHexTerrainType.class);
    private final Bitmap hexSelectedBitmap;
    private final Bitmap hexHilightedBitmap;
    private final List<Bitmap> elevationBitmapList = new ArrayList<Bitmap>();

    public BattletechHexPainter(FlatHexGridMetrics flatHexGridMetrics, Resources resources)
    {
        this.flatHexGridMetrics = flatHexGridMetrics;

        // TODO: Make text size(s) based on DPI and hex scale or something...
        this.textPaint.setTextSize(this.flatHexGridMetrics.getHexWidth() / 7);
        this.textPaint.setTypeface(Typeface.MONOSPACE);
        this.textPaint.setColor(Color.BLACK);

        Paint fillPaint = new Paint();
        fillPaint.setColor(Color.GRAY);
        fillPaint.setStyle(Style.FILL);

        Paint borderPaint = new Paint();
        borderPaint.setColor(Color.BLACK);
        borderPaint.setStyle(Style.STROKE);

        // for (int terrainId : TERRAIN_IDS)
        // {
        // this.idBitmaps.put(terrainId, loadHexBitmap(resources, terrainId));
        // }

        // this.hexSelectedBitmap = loadHexBitmap(resources,
        // R.drawable.hex_borders);
        this.hexSelectedBitmap = loadHexBitmap(resources, borderPaint, R.drawable.artytarget);
        this.hexHilightedBitmap = loadHexBitmap(resources, borderPaint, R.drawable.fog);

        this.terrainBitmapMap.put(BattletechHexTerrainType.PLAINS,
                                  new Bitmap[] { loadHexBitmap(resources,
                                                               borderPaint,
                                                               R.drawable.beige_plains_1),
                                                loadHexBitmap(resources,
                                                              borderPaint,
                                                              R.drawable.grass_plains_0),
                                                loadHexBitmap(resources,
                                                              borderPaint,
                                                              R.drawable.grass_plains_4) });

        this.terrainBitmapMap.put(BattletechHexTerrainType.WATER,
                                  new Bitmap[] { loadHexBitmap(resources,
                                                               borderPaint,
                                                               R.drawable.beige_plains_0,
                                                               R.drawable.blue_water_1),
                                                loadHexBitmap(resources,
                                                              borderPaint,
                                                              R.drawable.grass_plains_0,
                                                              R.drawable.blue_water_2),
                                                loadHexBitmap(resources,
                                                              borderPaint,
                                                              R.drawable.beige_plains_0,
                                                              R.drawable.blue_water_4) });

        this.terrainBitmapMap.put(BattletechHexTerrainType.ROUGH,
                                  new Bitmap[] { loadHexBitmap(resources,
                                                               borderPaint,
                                                               R.drawable.rough_0),
                                                loadHexBitmap(resources,
                                                              borderPaint,
                                                              R.drawable.ultra_rough) });

        this.terrainBitmapMap.put(BattletechHexTerrainType.WOODS,
                                  new Bitmap[] { loadHexBitmap(resources,
                                                               borderPaint,
                                                               R.drawable.lf0),
                                                loadHexBitmap(resources,
                                                              borderPaint,
                                                              R.drawable.hf0) });

        this.elevationBitmapList.add(createElevationBitmap(0, fillPaint, borderPaint));
        this.elevationBitmapList.add(createElevationBitmap(1, fillPaint, borderPaint));
        this.elevationBitmapList.add(createElevationBitmap(2, fillPaint, borderPaint));
        this.elevationBitmapList.add(createElevationBitmap(3, fillPaint, borderPaint));
    }

    @Override
    public void paint(Canvas canvas,
                      int leftX,
                      int topY,
                      IHex hex,
                      boolean isSelected,
                      boolean isHilighted)
    {
        IBattletechHex battletechHex = (IBattletechHex) hex;
        List<? extends IBattletechHexTerrain> hexTerrainList = battletechHex.getHexTerrainList();
        int adjustedTopY = topY - battletechHex.getElevation() * 10;

        if ((hexTerrainList == null) || (hexTerrainList.size() == 0))
        {
            // TODO: This is an error?
            // What should we do about Terrain: Should PLAINS be no-terrain or
            // an explicit terrain)
            Log.w("INFO", "BattletechHexPainter.paint(): No hexTerrain for hex: " + hex);
            // canvas.drawBitmap(getTerrainBitmap(null), leftX, topY,
            // this.paint);
        }
        else
        {
            for (IBattletechHexTerrain hexTerrain : hexTerrainList)
            {
                // Log.w("INFO", "Plotting Terrian: " + hexTerrain);

                Bitmap[] terrainBitmaps = this.terrainBitmapMap.get(hexTerrain.getHexTerrainType());
                Bitmap terrainBitmap = terrainBitmaps[hexTerrain.getLevel()];

                if (terrainBitmap != null)
                    canvas.drawBitmap(terrainBitmap, leftX, adjustedTopY, this.bitmapPaint);
            }
        }

        if (isSelected)
            canvas.drawBitmap(this.hexSelectedBitmap, leftX, adjustedTopY, this.bitmapPaint);

        if (isHilighted)
            canvas.drawBitmap(this.hexHilightedBitmap, leftX, adjustedTopY, this.bitmapPaint);

        // TODO: Inject the Locale, and use a messages.properties (or
        // res/strings.xml) for common strings
        String coordStr = String.format(Locale.US,
                                        "%02d-%02d",
                                        hex.getHexCoordinate().getGridX(),
                                        hex.getHexCoordinate().getGridY());

        this.textPaint.getTextBounds(coordStr, 0, coordStr.length(), this.textBoundsRect);
        float textLeft = leftX
                         + this.flatHexGridMetrics.getHexWidth()
                         / 2
                         - this.textBoundsRect.width()
                         / 2
                         - this.textBoundsRect.left;
        // Origin = Bottom, not counting some letters dropping below the line (g, p, etc..)
        float textOrigin = adjustedTopY + (float) (this.flatHexGridMetrics.getHexHeight() * 0.9);

        // Paint fillPaint = new Paint();
        // fillPaint.setColor(Color.GRAY);
        // fillPaint.setStyle(Style.FILL);
        // // fillPaint.setAlpha(255);
        //
        // canvas.drawRect(textLeft - 2,
        // textOrigin - this.textBoundsRect.height() - 2,
        // textLeft + this.textBoundsRect.width() + 4,
        // textOrigin + 2,
        // fillPaint);

        canvas.drawText(coordStr, textLeft, textOrigin, this.textPaint);

        if (battletechHex.getElevation() > 0)
        {
            canvas.drawBitmap(this.elevationBitmapList.get(battletechHex.getElevation()),
                              leftX,
                              adjustedTopY,
                              this.bitmapPaint);
        }
    }

    /**
     * Function to set the specified Drawable as the tile for a particular integer index.
     */
    private Bitmap loadHexBitmap(Resources resources,
                                 Paint borderPaint,
                                 int... hexBitmapIds)
    {
        Bitmap bitmap = Bitmap.createBitmap(this.flatHexGridMetrics.getHexWidth(),
                                            this.flatHexGridMetrics.getHexHeight(),
                                            Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);

        for (int hexBitmapId : hexBitmapIds)
        {
            Drawable hexDrawable = resources.getDrawable(hexBitmapId);
            hexDrawable.setBounds(0,
                                  0,
                                  this.flatHexGridMetrics.getHexWidth(),
                                  this.flatHexGridMetrics.getHexHeight());
            hexDrawable.draw(canvas);
        }

        canvas.drawLine(0,
                        this.flatHexGridMetrics.getHexHalfHeight(),
                        this.flatHexGridMetrics.getHexQuarterWidth(),
                        0,
                        borderPaint);
        canvas.drawLine(this.flatHexGridMetrics.getHexQuarterWidth(),
                        0,
                        this.flatHexGridMetrics.getHexThreeQuartersWidth(),
                        0,
                        borderPaint);
        canvas.drawLine(this.flatHexGridMetrics.getHexThreeQuartersWidth(),
                        0,
                        this.flatHexGridMetrics.getHexWidth(),
                        this.flatHexGridMetrics.getHexHalfHeight(),
                        borderPaint);

        return bitmap;
    }

    private Bitmap createElevationBitmap(int elevation,
                                         Paint fillPaint,
                                         Paint borderPaint)
    {
        int elevationHeight = elevation * this.flatHexGridMetrics.getHexElevationHeight();

        Bitmap bitmap = Bitmap.createBitmap(this.flatHexGridMetrics.getHexWidth() + 1,
                                            this.flatHexGridMetrics.getHexHeight()
                                                    + elevationHeight
                                                    + 1,
                                            Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);

        Path polyPath = new Path();
        polyPath.moveTo(0, this.flatHexGridMetrics.getHexHalfHeight());
        polyPath.lineTo(this.flatHexGridMetrics.getHexQuarterWidth(),
                        this.flatHexGridMetrics.getHexHeight());
        polyPath.lineTo(this.flatHexGridMetrics.getHexQuarterWidth(),
                        this.flatHexGridMetrics.getHexHeight() + elevationHeight);
        polyPath.lineTo(0, this.flatHexGridMetrics.getHexHalfHeight() + elevationHeight);
        polyPath.close();

        canvas.drawPath(polyPath, fillPaint);
        canvas.drawPath(polyPath, borderPaint);

        polyPath.reset();
        polyPath.moveTo(this.flatHexGridMetrics.getHexWidth(),
                        this.flatHexGridMetrics.getHexHalfHeight());
        polyPath.lineTo(this.flatHexGridMetrics.getHexThreeQuartersWidth(),
                        this.flatHexGridMetrics.getHexHeight());
        polyPath.lineTo(this.flatHexGridMetrics.getHexThreeQuartersWidth(),
                        this.flatHexGridMetrics.getHexHeight() + elevationHeight);
        polyPath.lineTo(this.flatHexGridMetrics.getHexWidth(),
                        this.flatHexGridMetrics.getHexHalfHeight() + elevationHeight);
        polyPath.close();

        canvas.drawPath(polyPath, fillPaint);
        canvas.drawPath(polyPath, borderPaint);

        polyPath.reset();
        polyPath.moveTo(this.flatHexGridMetrics.getHexQuarterWidth(),
                        this.flatHexGridMetrics.getHexHeight());
        polyPath.lineTo(this.flatHexGridMetrics.getHexThreeQuartersWidth(),
                        this.flatHexGridMetrics.getHexHeight());
        polyPath.lineTo(this.flatHexGridMetrics.getHexThreeQuartersWidth(),
                        this.flatHexGridMetrics.getHexHeight() + elevationHeight);
        polyPath.lineTo(this.flatHexGridMetrics.getHexQuarterWidth(),
                        this.flatHexGridMetrics.getHexHeight() + elevationHeight);
        polyPath.close();

        canvas.drawPath(polyPath, fillPaint);
        canvas.drawPath(polyPath, borderPaint);

        polyPath.reset();
        polyPath.moveTo(this.flatHexGridMetrics.getHexQuarterWidth(),
                        this.flatHexGridMetrics.getHexHeight());
        polyPath.lineTo(this.flatHexGridMetrics.getHexThreeQuartersWidth(),
                        this.flatHexGridMetrics.getHexHeight());
        polyPath.lineTo(this.flatHexGridMetrics.getHexThreeQuartersWidth(),
                        this.flatHexGridMetrics.getHexHeight() + elevationHeight);
        polyPath.lineTo(this.flatHexGridMetrics.getHexQuarterWidth(),
                        this.flatHexGridMetrics.getHexHeight() + elevationHeight);
        polyPath.close();

        // Handled in the Terrain Bitmaps
        // canvas.drawLine(0, this.flatHexGridMetrics.getHexHalfHeight(), this.flatHexGridMetrics.getHexQuarterWidth(),
        // 0,
        // borderPaint);
        // canvas.drawLine(this.flatHexGridMetrics.getHexQuarterWidth(), 0,
        // this.flatHexGridMetrics.getHexThreeQuartersWidth(),
        // 0, borderPaint);
        // canvas.drawLine(this.flatHexGridMetrics.getHexThreeQuartersWidth(),
        // 0,
        // this.flatHexGridMetrics.getHexWidth(),
        // this.flatHexGridMetrics.getHexHalfHeight(),
        // borderPaint);

        return bitmap;
    }
}

//
// private final Path lhsPolyPath = new Path();
// private final Path rhsPolyPath = new Path();
// private final Path centerPolyPath = new Path();
//
// this.lhsPolyPath.reset();
// this.lhsPolyPath.moveTo(leftX, adjustedTopY + this.flatHexGridMetrics.getHexHalfHeight());
// this.lhsPolyPath.lineTo(leftX + this.flatHexGridMetrics.getHexQuarterWidth(), adjustedTopY +
// this.flatHexGridMetrics.getHexHeight());
// this.lhsPolyPath.lineTo(leftX + this.flatHexGridMetrics.getHexQuarterWidth(), topY +
// this.flatHexGridMetrics.getHexHeight());
// this.lhsPolyPath.lineTo(leftX, topY + this.flatHexGridMetrics.getHexHalfHeight());
// this.lhsPolyPath.close();
//
// this.rhsPolyPath.reset();
// this.rhsPolyPath.moveTo(leftX + this.flatHexGridMetrics.getHexWidth(), adjustedTopY +
// this.flatHexGridMetrics.getHexHalfHeight());
// this.rhsPolyPath.lineTo(leftX + this.flatHexGridMetrics.getHexThreeQuartersWidth(),
// adjustedTopY + this.flatHexGridMetrics.getHexHeight());
// this.rhsPolyPath.lineTo(leftX + this.flatHexGridMetrics.getHexThreeQuartersWidth(), topY +
// this.flatHexGridMetrics.getHexHeight());
// this.rhsPolyPath.lineTo(leftX + this.flatHexGridMetrics.getHexWidth(), topY +
// this.flatHexGridMetrics.getHexHalfHeight());
// this.rhsPolyPath.close();
//
// this.centerPolyPath.reset();
// this.centerPolyPath.moveTo(leftX + this.flatHexGridMetrics.getHexQuarterWidth(), adjustedTopY
// + this.flatHexGridMetrics.getHexHeight());
// this.centerPolyPath.lineTo(leftX + this.flatHexGridMetrics.getHexThreeQuartersWidth(),
// adjustedTopY
// + this.flatHexGridMetrics.getHexHeight());
// this.centerPolyPath.lineTo(leftX + this.flatHexGridMetrics.getHexThreeQuartersWidth(), topY +
// this.flatHexGridMetrics.getHexHeight());
// this.centerPolyPath.lineTo(leftX + this.flatHexGridMetrics.getHexQuarterWidth(), topY +
// this.flatHexGridMetrics.getHexHeight());
// this.centerPolyPath.close();
//
// // canvas.drawPath(this.lhsPolyPath, this.fillPaint);
// // canvas.drawPath(this.rhsPolyPath, this.fillPaint);
// // canvas.drawPath(this.centerPolyPath, this.fillPaint);
// //
// // canvas.drawPath(this.lhsPolyPath, this.borderPaint);
// // canvas.drawPath(this.rhsPolyPath, this.borderPaint);
// // canvas.drawPath(this.centerPolyPath, this.borderPaint);